/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dameki.ki;

import dameki.core.GlobalVars;
import dameki.game.GameMove;
import dameki.game.Stone;
import dameki.game.player.Player;
import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author Tobi
 */
public class Agent extends Player {

//    private ArrayList<Stone> stones;
//    private Controller control;
//    private boolean color;
    private int col;
    private Random rand;
    private int[] enemypos;
    private int savecol;
    private boolean savecolor;
    private int stepdownlevel;
    private int modulo;
    

    public Agent(boolean color) {
        super(color);
        this.savecolor = color;
        col = 1;
        savecol = 1;
        if (!color) {
            col = -1;
            savecol = -1;
        }
        this.enemypos = new int[]{-1, -1};
        rand = new Random();
        
        stepdownlevel = 6;
        modulo = stepdownlevel%2;        
    }

    @Override
    public GameMove[] move(Stone[][] field) {
        //GENERATE THE INTELLIGENT AGENTS MOVEMENT IN HERE
        this.enemypos = getEnemyPos(field);
        ArrayList<ValuedGameMove> vgm = new ArrayList<>();
        for (Stone s : stones) {
            ValuedGameMove m = calcStonePoints(s, field, null, null,stepdownlevel);
            if (m != null) {
                if (vgm.isEmpty()) {
                    vgm.add(m);
                } else {
                    if (vgm.get(0) == null || vgm.get(0).getValue() < m.getValue()) {
                        vgm.add(0, m);
                    } else {
                        vgm.add(m);
                    }
                }
            }
        }
        if (vgm.isEmpty()) {
            return null;
        }
        ArrayList<ValuedGameMove> res = new ArrayList<>();
        for (ValuedGameMove v : vgm) {
            if (v.getValue() == vgm.get(0).getValue() && v.getMoves() != null) {
                res.add(v);
            }
        }
        if (res.isEmpty()) {
            return null;
        } else {
            return res.get(rand.nextInt(res.size())).getMoves();
        }

        //return vgm.get(0).getMoves();
    }

    private ValuedGameMove calcStonePoints(Stone s, Stone[][] field, Stone killed, int[] pos,int level) {
        ValuedGameMove gmove = new ValuedGameMove();
        boolean jumped = false;
        if (killed != null) {
            jumped = true;
        }
        int posX;
        int posY;
        
        if (pos != null) {
            posY = pos[0];
            posX = pos[1];
        } else {
            posX = s.getPosX();
            posY = s.getPosY();
        }
        if((level%2)==modulo){
            col = savecol;
            color = savecolor;
        }else{
            col = savecol==1?-1:1;   
            color = savecolor?false:true;            
        }
        level--;
        
        //if no Dame
        try {
            //top right empty//bottom left
            if (field[posY + col][posX + 1] == null) {
                if (!jumped){
                    ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY + col, posX + 1), GlobalVars.STONE_MOVED + checkField(posY + col, posX + 1, s, field,level));
                    if (move.getValue() > gmove.getValue()) {
                        gmove = move;
                    } else if (move.getValue() == gmove.getValue()) {
                        if (gmove.getMoves() == null || neartoEnemy(move.getMoves()[0].getPosY(), move.getMoves()[0].getPosX(), gmove.getMoves()[0].getPosY(), gmove.getMoves()[0].getPosX())) {
                            gmove = move;
                        }
                    }
                }
            }//enemy at top right
            else if (field[posY + col][posX + 1].getColor() != s.getColor() && field[posY + col][posX + 1] != killed) {
                //no stone at 2top 2right
                if (field[posY + 2 * col][posX + 2] == null) {
                    
                    GameMove m = new GameMove(s, posY + 2 * col, posX + 2);
                    ValuedGameMove second = calcStonePoints(s, field, field[posY + col][posX + 1], new int[]{posY + 2 * col, posX + 2},level);
                    ValuedGameMove move;
                    if(second!=null){
                        move = new ValuedGameMove(m, GlobalVars.STONE_KILLEDTWICE);
                        move.joinValuedGameMoves(second);
                    }else{
                        move = new ValuedGameMove(m, GlobalVars.STONE_KILLED + checkField(posY + 2 * col, posX + 2, s, field,level));
                    }                    
//                    ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY + 2 * col, posX + 2), GlobalVars.STONE_KILLED + checkField(posY + 2 * col, posX + 2, s, field,level));
//                    move.joinValuedGameMoves(calcStonePoints(s, field, field[posY + col][posX + 1], new int[]{posY + 2 * col, posX + 2},level));
                    if (move.getValue() > gmove.getValue() || rand.nextBoolean() && move.getValue() == gmove.getValue()) {
                        gmove = move;
                    }
                }
            }
        } catch (IndexOutOfBoundsException ex) {
        }
        try {
            //top left empty
            if (field[posY + col][posX - 1] == null) {
                if (!jumped){
                    ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY + col, posX - 1), GlobalVars.STONE_MOVED + checkField(posY + col, posX - 1, s, field,level));
                    //if (move.getValue() > gmove.getValue() || rand.nextBoolean() && move.getValue() == gmove.getValue()) {
                    if (move.getValue() > gmove.getValue()) {
                        gmove = move;
                    } else if (move.getValue() == gmove.getValue()) {
                        if (gmove.getMoves() == null || neartoEnemy(move.getMoves()[0].getPosY(), move.getMoves()[0].getPosX(), gmove.getMoves()[0].getPosY(), gmove.getMoves()[0].getPosX())) {
                            gmove = move;
                        }
                    }
                }
            } //enemy at top left // top right
            else if (field[posY + col][posX - 1].getColor() != s.getColor() && field[posY + col][posX - 1] != killed) {
                //no stone at 2top 2left
                if (field[posY + 2 * col][posX - 2] == null) {                    
                    GameMove m = new GameMove(s, posY + 2 * col, posX - 2);
                    ValuedGameMove second = calcStonePoints(s, field, field[posY + col][posX - 1], new int[]{posY + 2 * col, posX - 2},level);
                    ValuedGameMove move;
                    if(second!=null){
                        move = new ValuedGameMove(m, GlobalVars.STONE_KILLEDTWICE);
                        move.joinValuedGameMoves(second);
                    }else{
                        move = new ValuedGameMove(m, GlobalVars.STONE_KILLED + checkField(posY + 2 * col, posX - 2, s, field,level));
                    }                    
//                    ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY + 2 * col, posX - 2), GlobalVars.STONE_KILLED + checkField(posY + 2 * col, posX - 2, s, field,level));
//                    move.joinValuedGameMoves(calcStonePoints(s, field, field[posY + col][posX - 1], new int[]{posY + 2 * col, posX - 2},level));
                    if (move.getValue() > gmove.getValue() || rand.nextBoolean() && move.getValue() == gmove.getValue()) {
                        gmove = move;
                    }
                }
            }
        } catch (IndexOutOfBoundsException ex) {
        }
        //if Dame
        if (s.IsDame()) {
            try {
                //top right empty
                if (field[posY - col][posX + 1] == null) {
                    if (!jumped){
                        ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY - col, posX + 1), GlobalVars.STONE_MOVED + checkField(posY - col, posX + 1, s, field,level));
                        //if (move.getValue() > gmove.getValue() || rand.nextBoolean() && move.getValue() == gmove.getValue()) {
                        if (move.getValue() > gmove.getValue()) {
                            gmove = move;
                        } else if (move.getValue() == gmove.getValue()) {
                            if (gmove.getMoves() == null || neartoEnemy(move.getMoves()[0].getPosY(), move.getMoves()[0].getPosX(), gmove.getMoves()[0].getPosY(), gmove.getMoves()[0].getPosX())) {
                                gmove = move;
                            }
                        }
                    }
                }//enemy at top right
                else if (field[posY - col][posX + 1].getColor() != s.getColor() && field[posY - col][posX + 1] != killed) {
                    //no stone at 2top 2right
                    if (field[posY - 2 * col][posX + 2] == null) {
                        
                        GameMove m = new GameMove(s, posY - 2 * col, posX + 2);
                        ValuedGameMove second = calcStonePoints(s, field, field[posY - col][posX + 1], new int[]{posY - 2 * col, posX + 2},level);
                        ValuedGameMove move;
                        if(second!=null){
                            move = new ValuedGameMove(m, GlobalVars.STONE_KILLEDTWICE);
                            move.joinValuedGameMoves(second);
                        }else{
                            move = new ValuedGameMove(m, GlobalVars.STONE_KILLED + checkField(posY - 2 * col, posX + 2, s, field,level));
                        }     
//                        ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY - 2 * col, posX + 2), GlobalVars.STONE_KILLED + checkField(posY - 2 * col, posX + 2, s, field,level));
//                        move.joinValuedGameMoves(calcStonePoints(s, field, field[posY - col][posX + 1], new int[]{posY - 2 * col, posX + 2},level));
                        if (move.getValue() > gmove.getValue() || rand.nextBoolean() && move.getValue() == gmove.getValue()) {
                            gmove = move;
                        }
                    }
                }
            } catch (IndexOutOfBoundsException ex) {
            }
            try {
                //top left empty
                if (field[posY - col][posX - 1] == null) {
                    if (!jumped){
                        ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY - col, posX - 1), GlobalVars.STONE_MOVED + checkField(posY - col, posX - 1, s, field,level));
                        //if (move.getValue() > gmove.getValue() || rand.nextBoolean() && move.getValue() == gmove.getValue()) {
                        if (move.getValue() > gmove.getValue()) {
                            gmove = move;
                        } else if (move.getValue() == gmove.getValue()) {
                            if (gmove.getMoves() == null || neartoEnemy(move.getMoves()[0].getPosY(), move.getMoves()[0].getPosX(), gmove.getMoves()[0].getPosY(), gmove.getMoves()[0].getPosX())) {
                                gmove = move;
                            }
                        }
                    }
                } //enemy at top left // top right
                else if (field[posY - col][posX - 1].getColor() != s.getColor() && field[posY - col][posX - 1] != killed) {
                    //no stone at 2top 2left
                    if (field[posY - 2 * col][posX - 2] == null) {
                        GameMove m = new GameMove(s, posY - 2 * col, posX - 2);
                        ValuedGameMove second = calcStonePoints(s, field, field[posY - col][posX - 1], new int[]{posY - 2 * col, posX - 2},level);
                        ValuedGameMove move;
                        if(second!=null){
                            move = new ValuedGameMove(m, GlobalVars.STONE_KILLEDTWICE);
                            move.joinValuedGameMoves(second);
                        }else{
                            move = new ValuedGameMove(m, GlobalVars.STONE_KILLED + checkField(posY - 2 * col, posX - 2, s, field,level));
                        }
                        //ValuedGameMove move = new ValuedGameMove(new GameMove(s, posY - 2 * col, posX - 2), GlobalVars.STONE_KILLED + checkField(posY - 2 * col, posX - 2, s, field,level));
                        //move.joinValuedGameMoves(calcStonePoints(s, field, field[posY - col][posX - 1], new int[]{posY - 2 * col, posX - 2},level));
                        if (move.getValue() > gmove.getValue() || rand.nextBoolean() && move.getValue() == gmove.getValue()) {
                            gmove = move;
                        }
                    }
                }
            } catch (IndexOutOfBoundsException ex) {
            }
        }
         this.col = savecol;
         this.color = savecolor;
        if (gmove.getMoves() == null) {
            return null;
        } else {
            return gmove;
        }
        
       
    }

    private int checkField(int y, int x, Stone s, Stone[][] field,int level) {
        int value = 0;
        //fields left above is empty
        if (getStone(y + col, x - 1, field) == null || getStone(y + col, x - 1, field).equals(s)) {
            value += GlobalVars.STONE_SAVELY_MOVED;
        } //friend left above
        else if (getStone(y + col, x - 1, field).getColor() == this.getColor() && getStone(y + col, x - 1, field) != s) {
            //save stone
            if (getStone(y + 2 * col, x - 2, field) != null && getStone(y + 2 * col, x - 2, field).getColor() != this.getColor()) {
                value += GlobalVars.STONE_SAVED;
            } //savely moved
            else {
                value += GlobalVars.STONE_SAVELY_MOVED;
            }
        } //enemy left above
        else if (getStone(y + col, x - 1, field).getColor() != this.getColor()) {
            //friend/enemy right below (saves from beeing killed in next round)
            if (getStone(y - col, x + 1, field) != null && getStone(y - col, x + 1, field) != s) {
                value += GlobalVars.STONE_SAVELY_MOVED;
            }//field right below is empty (next round killed...)
            else if (getStone(y - col, x + 1, field) == null || getStone(y - col, x + 1, field) == s) {
                value += GlobalVars.STONE_UNSAVELY_MOVED;
            }
        }
        //fields right above is empty
        if (getStone(y + col, x + 1, field) == null || getStone(y + col, x + 1, field).equals(s)) {
            value += GlobalVars.STONE_SAVELY_MOVED;
        } //friend right above
        else if (getStone(y + col, x + 1, field).getColor() == this.getColor() && getStone(y + col, x + 1, field) != s) {
            //save stone
            if (getStone(y + 2 * col, x + 2, field) != null && getStone(y + 2 * col, x + 2, field).getColor() != this.getColor()) {
                value += GlobalVars.STONE_SAVED;
            } //savely moved
            else {
                value += GlobalVars.STONE_SAVELY_MOVED;
            }
        } //enemy right above
        else if (getStone(y + col, x + 1, field).getColor() != this.getColor()) {
            //friend/enemy left below (saves from beeing killed in next round)
            if (getStone(y - col, x - 1, field) != null && getStone(y - col, x - 1, field) != s) {
                value += GlobalVars.STONE_SAVELY_MOVED;
            }//field right below is empty (next round killed...)
            else if (getStone(y - col, x - 1, field) == null || getStone(y - col, x - 1, field) == s) {
                value += GlobalVars.STONE_UNSAVELY_MOVED;
            }
        }
        //if dame left below
        if (getStone(y - col, x - 1, field) != null && getStone(y - col, x - 1, field).IsDame() && getStone(y - col, x - 1, field).getColor() != this.color) {
            //friend/enemy right above (saves from beeing killed in next round)
            if (getStone(y + col, x + 1, field) != null && getStone(y + col, x + 1, field) != s) {
                value += GlobalVars.STONE_SAVELY_MOVED;
            }//field right below is empty (next round killed...)
            else if (getStone(y + col, x + 1, field) == null || getStone(y + col, x + 1, field) == s) {
                value += GlobalVars.STONE_UNSAVELY_MOVED;
            }
        }//save left below
        else {
            value += GlobalVars.STONE_SAVELY_MOVED;
        }
        //if dame right below
        if (getStone(y - col, x + 1, field) != null && getStone(y - col, x + 1, field).IsDame() && getStone(y - col, x + 1, field).getColor()!=this.color) {
            //friend/enemy left above (saves from beeing killed in next round)
            if (getStone(y + col, x - 1, field) != null && getStone(y + col, x - 1, field) != s) {
                value += GlobalVars.STONE_SAVELY_MOVED;
            }//field right below is empty (next round killed...)
            else if (getStone(y + col, x - 1, field) == null || getStone(y + col, x - 1, field) == s) {
                value += GlobalVars.STONE_UNSAVELY_MOVED;
            }
        }//save left below
        else {
            value += GlobalVars.STONE_SAVELY_MOVED;
        }
        
        //Simulate EnemyMove
        Stone[][] tempfield = new Stone[8][8];
        for(int z=0;z<field.length;z++){
            System.arraycopy(field[z], 0, tempfield[z], 0, field[z].length);
        }
        
        tempfield[s.getPosY()][s.getPosX()] = null;
        tempfield[y][x]=s;
        if(s.getPosY()-y==-2*col){
            if(s.getPosX()-x==-2){
                tempfield[y-col][x-1] = null;
            }else if(s.getPosX()-x==2){
                tempfield[y-col][x+1] = null;
            }
        }else if(s.getPosY()-y==2*col){
            if(s.getPosX()-x==-2){
                tempfield[y+col][x-1] = null;
            }else if(s.getPosX()-x==2){
                tempfield[y+col][x+1] = null;
            }
        }        
        if (level>0) {            
            ArrayList<Stone> enemys = getEnemyStones(tempfield);
            ValuedGameMove enem = new ValuedGameMove();
            for (Stone st : enemys) {
                ValuedGameMove temp = calcStonePoints(st, tempfield, null, null, level);
                if (temp != null && temp.getValue() > enem.getValue()) {
                    enem = temp;
                }
            }            
            value = value - enem.getValue()/2;
        }
        return value;
    }

    private Stone getStone(int y, int x, Stone[][] field) {
        try {
            return field[y][x];
        } catch (IndexOutOfBoundsException ex) {
            return null;
        }
    }

    private int[] getEnemyPos(Stone[][] field) {
        int[] pos = new int[]{0, 0};
        int count = 0;
        for (int x = 0; x < field.length; x++) {
            for (int y = 0; y < field[x].length; y++) {
                if (field[x][y] != null && field[x][y].getColor() != this.getColor()) {
                    pos[0] += field[x][y].getPosY();
                    pos[1] += field[x][y].getPosX();
                    count++;
                }
            }
        }
        if (count > 0) {
            pos[0] = pos[0] / count;
            pos[1] = pos[1] / count;
            return pos;
        } else {
            return new int[]{-1, -1};
        }
    }

    private boolean neartoEnemy(int pos1Y, int pos1X, int pos2Y, int pos2X) {
        return true;
        //        double dis1 = Math.sqrt(Math.pow(pos1Y - enemypos[0], 2) + Math.pow(pos1X - enemypos[1], 2));
//        double dis2 = Math.sqrt(Math.pow(pos2Y - enemypos[0], 2) + Math.pow(pos2X - enemypos[1], 2));
//
//        if (dis1 < dis2) {
//            return true;
//        } else {
//            return false;
//        }
    }
    
    private ArrayList<Stone> getEnemyStones(Stone[][] field){
        ArrayList list =  new ArrayList();
        for(int x=0;x<field.length;x++){
            for(int y=0;y<field[x].length;y++){
                if(field[x][y]!=null && field[x][y].getColor()!=this.getColor()){
                    list.add(field[x][y]);
                }
            }
        }
        return list;
    }
}
